"""贝叶斯分类是一种统计学分类方法，基于贝叶斯定理，对给定的数据集进行分类。
它的历史可以追溯到18世纪，当时英国统计学家托马斯·贝叶斯发展了贝叶斯定理，这个定理为统计决策提供了理论基础。

不过，贝叶斯分类在实际应用中的广泛使用是在20世纪80年代，当时计算机技术的进步使得大规模数据处理成为可能。

1. 算法概述
贝叶斯分类基于贝叶斯公式，通过已知样本信息来计算未知样本属于各个类别的概率，然后选择概率最大的类别作为未知样本的分类结果。

贝叶斯公式的简化公式：
P(A|B)=P(B|A)P(A)/P(B)其中：P(A)：事件A发生的概率P(B)：事件B发生的概率P(A|B)：在事件B出现的前提下，A发生的概率P(B|A)
：在事件A出现的前提下，B发生的概率
贝叶斯分类就是基于这个公式扩展而来。
比如，一个具有
n个特征的样本x=(x1,x2,...,xn)，该样本属于K个可能的类别y1,y2,...,yk。那么，任一个样本x属于某个类别yk的概率为：P(yk|x)=P(X|yk)P(yk)/P(x)
根据这个模型，训练样本之后，就可以根据模型来预测某个样本属于哪个类别的概率最大。

这里讨论的贝叶斯分类算法，并没有考虑特征之间的关联关系，我们假设每个特征之间是相互独立的。
所以，这个算法也叫做朴素贝叶斯分类。

2. 创建样本数据
贝叶斯分类可以
这次用scikit-learn中的样本生成器make_classification来生成分类用的样本数据。"""

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_classification
from sklearn import preprocessing as pp
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import (
    GaussianNB,
    MultinomialNB,
    ComplementNB,
    BernoulliNB,
    CategoricalNB,
)
import matplot_config

matplot_config.init_config()
# 分类数据的样本生成器
X, y = make_classification(n_samples=1000, n_classes=4, n_informative=3)
plt.scatter(X[:, 0], X[:, 1], marker="o", c=y, s=25)

plt.show()
"""image.png
关于样本生成器的详细内容，请参考：TODO

3. 模型训练
训练之前，为了减少算法误差，先对数据进行标准化处理（将数据缩放到0~100之间）。
"""
# 数据标准化
X = pp.minmax_scale(X, feature_range=(1, 100))
y = pp.minmax_scale(y, feature_range=(1, 100))
# 然后，分割训练集和测试集。


# 分割训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
"""按照8:2的比例来划分训练集和测试集。

scikit-learn中的朴素贝叶斯算法支持多种不同的分类器，
这些分类器基于不同的先验概率分布，适用于不同的数据类型和问题场景。
我们训练模型的时候要根据数据情况选择合适的分类器。
"""


reg_names = [
    "高斯朴素贝叶斯",
    "多项式朴素贝叶斯",
    "补码朴素贝叶斯",
    "伯努利朴素贝叶斯",
    "分类朴素贝叶斯",
]

# 定义
regs = [
    GaussianNB(),
    MultinomialNB(),
    ComplementNB(),
    BernoulliNB(),
    CategoricalNB(min_categories=101),
]

# 训练模型
for reg in regs:
    reg.fit(X_train, y_train)

"""各个分类器的简要说明：

GaussianNB：基于高斯分布的朴素贝叶斯分类器。它假设每个特征服从高斯分布，即正态分布。这种分类器适用于连续型数据，特别是对于数值型特征。
MultinomialNB：基于多项式分布的朴素贝叶斯分类器。它假设每个特征服从多项式分布，适用于离散型数据，特别是对于类别型特征。
ComplementNB：基于互补分布的朴素贝叶斯分类器。它适用于离散型数据，特别是对于二元分类问题。
BernoulliNB：基于伯努利分布的朴素贝叶斯分类器。它适用于二元分类问题，特别是对于二元特征或者二元输出。
CategoricalNB：基于分类分布的朴素贝叶斯分类器。它适用于离散型数据，特别是对于类别型特征。
最后验证各个分类器的模型的训练效果："""

# 在测试集上进行预测
y_preds = []
y_pred = None
for reg in regs:
    y_pred = reg.predict(X_test)
    y_preds.append(y_pred)

for i in range(len(y_preds)):
    correct_pred = np.sum(y_preds[i] == y_test)
    print("【{}】 预测正确率：{:.2f}%".format(reg_names[i],
                                      correct_pred / len(y_pred) * 100))

"""# 运行结果
【高斯朴素贝叶斯】 预测正确率：82.50%
【多项式朴素贝叶斯】 预测正确率：75.00%
【补码朴素贝叶斯】 预测正确率：72.50%
【伯努利朴素贝叶斯】 预测正确率：22.00%
【分类朴素贝叶斯】 预测正确率：50.50%
这里虽然高斯朴素贝叶斯分类器的正确率最高，但不能就认为这种分类器是最好的。
只能说明高斯朴素贝叶斯分类器最适合分类上面随机生成的样本数据。
换成其他的样本数据，高斯朴素贝叶斯分类器的正确率就不一定是最高的了。

4. 总结
总的来说，贝叶斯分类是一种有效的分类方法，适用于对未知样本进行分类的问题。
它的应用范围广泛，可以处理多分类问题，也可以用于连续变量的分类。

贝叶斯分类算法的主要优势在于：

是一种概率模型，可以给出分类结果的概率，因此更加可靠和稳定。
可以处理多分类问题，也可以用于连续变量的分类。
实现相对简单，可以在较短的时间内训练出模型并进行预测。
贝叶斯分类算法也有其不足之处：

假设所有特征之间相互独立，但在实际应用中这个假设往往不成立，因此会影响分类结果的准确性。
对于大规模的数据集，训练时间和预测时间可能会较长。
对于数据的缺失和异常值处理不够鲁棒，可能会对分类结果产生影响。"""